/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package servlet;

import BusinessLogic.Constants;
import BusinessLogic.PartnerBeanLocal;
import BusinessLogic.TCubeBeanLocal;
import EntityState.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import javax.ejb.EJB;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 *
 * @author James
 */
@WebServlet(name = "TCubeServlet", urlPatterns = {"/TCubeServlet"})
public class TCubeServlet extends HttpServlet {

    /** 
     * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @EJB
    private TCubeBeanLocal tcubeBean;
    @EJB
    private PartnerBeanLocal partnerBean;
    
    private ArrayList data = null;
    private List<TCubePrivilegeState> fullListOfPrivileges;
    
    @Override
    public void init() {
        System.out.println("TCubeServlet: init()");
        fullListOfPrivileges = tcubeBean.getFullListOfPrivileges();
    }
    
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        RequestDispatcher dispatcher;
        ServletContext servletContext = getServletContext();

        String page = request.getPathInfo();
        page        = page.substring(1);
        System.out.println("TCubeServlet: " + page);
        
        if (page.equals("") || page.equals("index")) {
            //nothing to do
            page = "index";
            
        } else if (page.equals("TCubeAccountRegistration")) {
            data = (ArrayList) fullListOfPrivileges;
            request.setAttribute("data", data);
            
        } else if (page.equals("CheckAvailability")) {
            data = checkAvailability(request);
            request.setAttribute("data", data);
            response.setContentType("text/xml");

            
        } else if (page.equals("TCubeAccountRegistrationStatus")) {
            data = registerAccount(request);
            request.setAttribute("data", data);
            
        } else if (page.equals("TCubeAccountActivate")) {
            data = activate(request);
            request.setAttribute("data", data);

        } else if (page.equals("TCubeLogin")) {
            data = login(request);
            request.setAttribute("data", data);

        } else if (page.equals("TCubeLoginStatus")) {
            data = login(request);
            request.setAttribute("data", data);

        } else if (page.equals("TCubePartnerRegistration")) {
            //nothing to do

        } else if (page.equals("TCubePartnerRegistrationStatus")) {
            data = registerPartner(request);
            request.setAttribute("data", data);

        } else if (page.equals("TCubePrivilegeCreation")) {
            //nothing to do

        } else if (page.equals("TCubePrivilegeCreationStatus")) {
            data = createTCubePrivilege(request);
            request.setAttribute("data", data);

        } else if (page.equals("TCubePrivilegeGrant")) {
            //nothing to do

        } else if (page.equals("TCubePrivilegeStatus")) {
            data = grantTCubePrivilege(request);
            request.setAttribute("data", data);

        } 
        
        if ((dispatcher = servletContext.getNamedDispatcher(page)) == null) dispatcher = servletContext.getNamedDispatcher("Error");
        else dispatcher.forward(request, response);
    }

    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /** 
     * Handles the HTTP <code>GET</code> method.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /** 
     * Handles the HTTP <code>POST</code> method.
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /** 
     * Returns a short description of the servlet.
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>

    private ArrayList grantTCubePrivilege(HttpServletRequest request) {
        ArrayList list = new ArrayList();
        
        TCubeAccountState tas = isSessionExpired(request);
        if (tas == null) list.add(Constants.STATUS_SESSION_EXPIRED);
        else if (!tcubeBean.checkPrivilege(tas.getUsername(), Constants.TCUBE_GRANT_PRIVILEGE)) list.add(Constants.STATUS_NOT_ALLOWED);
        else {
            //Get list of privileges granted
            String[] privileges = request.getParameterValues("privilege");
            int[] listOfPrivileges = new int[privileges.length];
            for (int i = 0 ; i < privileges.length ; i++) {
                listOfPrivileges[i] = Integer.parseInt(privileges[i]);
            }
            //Get username of the account granted
            String username;
            
            HashMap parameters = Utility.getCompulsoryParameters(request, "username");
            if (parameters.isEmpty()) list.add(Constants.STATUS_INVALID_INPUT);
            else if (!(username = (String) parameters.get("username")).equals(tas.getUsername()) || tcubeBean.checkAccountLevel(username, Constants.ACCOUNT_LEVEL_ROOT)) list.add(Constants.STATUS_NOT_ALLOWED); //Only root user can grant privileges to himself             
            else if (tcubeBean.checkAccountLevel(tas.getUsername(), username)) list.add(Constants.STATUS_NOT_ALLOWED); //A user cannot grant privilege to higher level account
            else list.add(tcubeBean.grantTCubePrivilege(username, listOfPrivileges));
        }
        
        return list;
    }
    
    private ArrayList createTCubePrivilege(HttpServletRequest request) {
        ArrayList list = new ArrayList();
        
        TCubeAccountState tas = isSessionExpired(request);
        if (tas == null) list.add(Constants.STATUS_SESSION_EXPIRED);
        else if (!tcubeBean.checkPrivilege(tas.getUsername(), Constants.TCUBE_CREATE_TCUBE_PRVILEGE)) list.add(Constants.STATUS_NOT_ALLOWED);
        else {
            String name, description;
            
            HashMap parameters = Utility.getCompulsoryParameters(request, "username");
            if (parameters.isEmpty()) list.add(Constants.STATUS_INVALID_INPUT);
            else {
                name        = (String) parameters.get("name");
                description = (String) parameters.get("description");
                list.add(tcubeBean.createTCubePrivilege(name, description));
            }
        }
        
        return list;
    }
    
    private ArrayList registerPartner(HttpServletRequest request) {
        ArrayList list = new ArrayList();
        
        TCubeAccountState tas = isSessionExpired(request);
        if (tas == null) list.add(Constants.STATUS_SESSION_EXPIRED);
        else if (!tcubeBean.checkPrivilege(tas.getUsername(), Constants.TCUBE_REGISTER_PARTNER)) list.add(Constants.STATUS_NOT_ALLOWED);
        else {
            //Firstly, create manager account
            String username, password, IC, firstName, lastName, gender, countryCode, phone, email, country, province, city, level;
            HashMap compulsory = Utility.getCompulsoryParameters(request, "level", "NRIC", "firstName", "lastName", "sex", "countryCode", "phone", "email1", "country", "chosenUsername", "password1");;
            HashMap optional   = Utility.getOptionalParameters(request, "province", "city");
            if (compulsory.isEmpty()) list.add(Constants.STATUS_INVALID_INPUT);
            else {
                username    = (String) compulsory.get("chosenUsername");
                password    = (String) compulsory.get("password1");
                IC          = (String) compulsory.get("NRIC");
                firstName   = (String) compulsory.get("firstName");
                lastName    = (String) compulsory.get("lastName");
                gender      = (String) compulsory.get("sex");
                countryCode = (String) compulsory.get("countryCode");
                phone       = (String) compulsory.get("phone");
                email       = (String) compulsory.get("email1");
                country     = (String) compulsory.get("country");
                province    = (String) optional.get("province");
                city        = (String) optional.get("city");
                level       = (String) compulsory.get("level");
                
                //Grant manage all Partner Privileges
                int[] privileges = new int[Constants.PARTNER_NUMBER_OF_PRIVILEGES];
                for (int i = 0 ; i < Constants.PARTNER_NUMBER_OF_PRIVILEGES ; i++) {
                    privileges[i] = i;
                }
                //Create the account
                int result = partnerBean.registerAccount(username, password, IC, firstName, lastName, gender, countryCode, phone, email, country, province, city, Integer.parseInt(level), privileges, 0, 0);
                if (result == Constants.STATUS_NOT_UNIQUE) list.add(result);
                else if (result == Constants.STATUS_SUCCESSFUL) {
                    //Next, create the Partner
                    String partnerName, partnerBizAddress1, partnerBizAddress2, partnerBizPostalCode, partnerBillingAddress1, partnerBillingAddress2, partnerBillingPostalCode, partnerCountryCode, partnerPhone, partnerCountry, partnerProvince, partnerCity, partnerBizEmail, partnerSector, partnerMotherCorpID;
                    
                    compulsory = Utility.getCompulsoryParameters(request, "partnerName", "partnerBizAddress1", "partnerBizAddress2", "partnerBizPostalCode", "partnerBillingAddress1", "partnerBillingAddress2", "partnerBillingPostalCode", "partnerCountryCode", "partnerPhone", "partnerCountry", "partnerBizEmail", "partnerSector");
                    optional   = Utility.getOptionalParameters(request, "partnerProvince", "partnerCity", "partnerMotherCorpID");
                    if (compulsory.isEmpty()) list.add(Constants.STATUS_INVALID_INPUT);
                    else {
                        partnerName              = (String) compulsory.get("partnerName");
                        partnerBizAddress1       = (String) compulsory.get("partnerBizAddress1");
                        partnerBizAddress2       = (String) compulsory.get("partnerBizAddress2");
                        partnerBizPostalCode     = (String) compulsory.get("partnerBizPostalCode");
                        partnerBillingAddress1   = (String) compulsory.get("partnerBillingAddress1");
                        partnerBillingAddress2   = (String) compulsory.get("partnerBillingAddress2");
                        partnerBillingPostalCode = (String) compulsory.get("partnerBillingPostalCode");
                        partnerCountryCode       = (String) compulsory.get("partnerCountryCode");
                        partnerPhone             = (String) compulsory.get("partnerPhone");
                        partnerCountry           = (String) compulsory.get("partnerCountry");
                        partnerProvince          = (String) optional.get("partnerProvince");
                        partnerCity              = (String) optional.get("partnerCity");
                        partnerBizEmail          = (String) compulsory.get("partnerBizEmail");
                        partnerSector            = (String) compulsory.get("partnerSector");
                        partnerMotherCorpID      = (String) optional.get("partnerMotherCorpID");
                        
                        if (partnerMotherCorpID.equals("")) list.add(tcubeBean.registerPartner(partnerName, partnerBizAddress1, partnerBizAddress2, partnerBizPostalCode, partnerBillingAddress1, partnerBillingAddress2, partnerBillingPostalCode, partnerCountryCode, partnerPhone, partnerCountry, partnerProvince, partnerCity, partnerBizEmail, Integer.parseInt(partnerSector), 0, username));
                        list.add(tcubeBean.registerPartner(partnerName, partnerBizAddress1, partnerBizAddress2, partnerBizPostalCode, partnerBillingAddress1, partnerBillingAddress2, partnerBillingPostalCode, partnerCountryCode, partnerPhone, partnerCountry, partnerProvince, partnerCity, partnerBizEmail, Integer.parseInt(partnerSector), Long.parseLong(partnerMotherCorpID), username));
                    }
                } else list.add(Constants.STATUS_UNEXPECTED_ERROR);
            }
        }
        
        return list;
    }
    
    private ArrayList checkAvailability(HttpServletRequest request) {
        ArrayList list = new ArrayList();
        String username = request.getParameter("target");
        list.add(tcubeBean.checkAvailability(username));
        return list;
    }
    
    private ArrayList registerAccount(HttpServletRequest request) {
        ArrayList list = new ArrayList();

        TCubeAccountState tas = isSessionExpired(request);
        if (tas == null) list.add(Constants.STATUS_SESSION_EXPIRED);
        else if (!tcubeBean.checkPrivilege(tas.getUsername(), Constants.TCUBE_CREATE_ACCOUNT)) list.add(Constants.STATUS_NOT_ALLOWED);
        else {
            //Get other information
            String level, theRole, IC, firstName, lastName, gender, countryCode, phone, country, city, email, username, password;
            HashMap parameters = Utility.getCompulsoryParameters(request, "level", "role", "NRIC", "firstName", "lastName", "sex", "countryCode", "phone", "country", "city", "email1", "chosenUsername", "password1");
            if (parameters.isEmpty()) list.add(Constants.STATUS_INVALID_INPUT);
            else {
                level       = (String) parameters.get("level");
                theRole     = (String) parameters.get("theRole");
                IC          = (String) parameters.get("IC");
                firstName   = (String) parameters.get("firstName");
                lastName    = (String) parameters.get("lastName");
                gender      = (String) parameters.get("gender");
                countryCode = (String) parameters.get("countryCode");
                phone       = (String) parameters.get("phone");
                country     = (String) parameters.get("country");
                city        = (String) parameters.get("city");
                email       = (String) parameters.get("email");
                username    = (String) parameters.get("username");
                password    = (String) parameters.get("password");
                
                //An admin cannot create account that is higher level than his own account
                int accountLevel = Integer.parseInt(level);
                if (accountLevel <= Constants.ACCOUNT_LEVEL_ROOT && tcubeBean.checkAccountLevel(tas.getUsername(), accountLevel)) list.add(tcubeBean.registerAccount(username, password, IC, firstName, lastName, gender, countryCode, phone, email, country, city, accountLevel, Integer.parseInt(theRole)));
                else list.add(Constants.STATUS_NOT_ALLOWED);
            }
        }
        
        return list;
    }

    private ArrayList activate(HttpServletRequest request) {
        ArrayList list = new ArrayList();
        String    id   = request.getParameter("id");
        list.add(tcubeBean.activateUser(id));
        return list;
    }

    private ArrayList login(HttpServletRequest request) {
        ArrayList list = new ArrayList();
        TCubeAccountState tas;

        //Check if user has logined recently
        if ((tas = isSessionExpired(request)) != null) {
            //Show him the user control panel 
            list.add(Constants.STATUS_SUCCESSFUL);
            list.add(tas.getUsername());
        } else {
            //If new user, try to get the Username and Password
            String username = request.getParameter("username");
            String password = request.getParameter("password");
            String timezone = request.getParameter("timezone");

            //If no Username was submitted, this is a new user
            if (username == null) list.add(Constants.STATUS_NEW_SESSION);
            else {
                //If a Username was submitted, look for an entry in the database
                tas = tcubeBean.login(username, password, timezone);
                if (tas == null) list.add(Constants.STATUS_WRONG_PASSWORD); //Wrong Username or Password
                else if (tas.isActivated() && tas.isActive()) { //If this user exitst, check if he activated his account
                    list.add(Constants.STATUS_SUCCESSFUL);
                    HttpSession clientSession = request.getSession();
                    clientSession.setMaxInactiveInterval(1800);
                    clientSession.setAttribute("staff", tas);
                    clientSession.setMaxInactiveInterval(86400);
                } else {
                    if (!tas.isActivated()) list.add(Constants.STATUS_USER_INACTIVATED);
                    else if (!tas.isActive()) list.add(Constants.STATUS_ACCOUNT_BANNED);
                    list.add(username);
                }
            }
        }
        return list;
    }
    
    //Utility function:
    private TCubeAccountState isSessionExpired(HttpServletRequest request) {
        HttpSession staffSession = request.getSession(false);
        TCubeAccountState tas;
        if (staffSession == null || (tas = (TCubeAccountState) staffSession.getAttribute("staff")) == null) return null;
        else return tas;
    }
}
